library(sf)           
Linking to GEOS 3.11.2, GDAL 3.6.2, PROJ 9.2.0; sf_use_s2() is TRUE
library(rgdal)        
Please note that rgdal will be retired during October 2023,
plan transition to sf/stars/terra functions using GDAL and PROJ
at your earliest convenience.
See https://r-spatial.org/r/2023/05/15/evolution4.html and https://github.com/r-spatial/evolution
rgdal: version: 1.6-7, (SVN revision 1203)
Geospatial Data Abstraction Library extensions to R successfully loaded
Loaded GDAL runtime: GDAL 3.6.2, released 2023/01/02
Path to GDAL shared files: C:/Users/jcolpitt/AppData/Local/R/win-library/4.3/rgdal/gdal
 GDAL does not use iconv for recoding strings.
GDAL binary built with GEOS: TRUE 
Loaded PROJ runtime: Rel. 9.2.0, March 1st, 2023, [PJ_VERSION: 920]
Path to PROJ shared files: C:\Program Files\PostgreSQL\15\share\contrib\postgis-3.3\proj
PROJ CDN enabled: FALSE
Linking to sp version:1.6-1
To mute warnings of possible GDAL/OSR exportToProj4() degradation,
use options("rgdal_show_exportToProj4_warnings"="none") before loading sp or rgdal.
library(ggplot2)      
library(dplyr)        

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(tidyr)        
library(scales)       
library(RColorBrewer) 
library(units)
udunits database from C:/Users/jcolpitt/AppData/Local/R/win-library/4.3/units/share/udunits/udunits2.xml
library(cowplot)
library(here)
here() starts at C:/Users/jcolpitt/SpatialDataScience/Rprojects/R
okcounty <- st_read(here("data", "ok_counties.shp"), quiet = TRUE)
tpoint <- st_read(here("data", "ok_tornado_point.shp"), quiet = TRUE)
tpath <- st_read(here("data", "ok_tornado_path.shp"), quiet = TRUE)

class(okcounty)
[1] "sf"         "data.frame"
glimpse(okcounty)
Rows: 77
Columns: 8
$ STATEFP  <chr> "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", …
$ COUNTYFP <chr> "077", "025", "011", "107", "105", "153", "001", "053", "059", "073", "129", "015", "097", "033", "147", "041", "109", "057", "133", "093", "031", "063", "075", "099", "141", "083", "069…
$ COUNTYNS <chr> "01101826", "01101800", "01101793", "01101841", "01101840", "01101864", "01101788", "01101814", "01101817", "01101824", "01101852", "01101795", "01101833", "01101804", "01101861", "01101…
$ AFFGEOID <chr> "0500000US40077", "0500000US40025", "0500000US40011", "0500000US40107", "0500000US40105", "0500000US40153", "0500000US40001", "0500000US40053", "0500000US40059", "0500000US40073", "05000…
$ GEOID    <chr> "40077", "40025", "40011", "40107", "40105", "40153", "40001", "40053", "40059", "40073", "40129", "40015", "40097", "40033", "40147", "40041", "40109", "40057", "40133", "40093", "40031…
$ NAME     <chr> "Latimer", "Cimarron", "Blaine", "Okfuskee", "Nowata", "Woodward", "Adair", "Grant", "Harper", "Kingfisher", "Roger Mills", "Caddo", "Mayes", "Cotton", "Washington", "Delaware", "Oklahom…
$ LSAD     <chr> "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", …
$ geometry <POLYGON [°]> POLYGON ((-95.50766 35.0292..., POLYGON ((-103.0025 36.6751..., POLYGON ((-98.6369 36.16489..., POLYGON ((-96.62486 35.4627..., POLYGON ((-95.80982 36.9419..., POLYGON ((-99.6055…
okcounty_sp <- as(okcounty, 'Spatial')
class(okcounty_sp)
[1] "SpatialPolygonsDataFrame"
attr(,"package")
[1] "sp"
okcounty_sf <- st_as_sf(okcounty_sp)
class(okcounty_sf)
[1] "sf"         "data.frame"
ggplot(data = okcounty) +
  geom_sf(fill = NA)

names(tpoint)
 [1] "om"       "yr"       "mo"       "dy"       "date"     "time"     "tz"       "st"       "stf"      "stn"     
[11] "mag"      "inj"      "fat"      "loss"     "closs"    "slat"     "slon"     "elat"     "elon"     "len"     
[21] "wid"      "fc"       "geometry"
tpoint_16_21 <- tpoint %>%
  filter(yr >= 2016 & yr <= 2021) %>%
  select(om, yr, date)

tpath_16_21 <- tpath %>%
  filter(yr >= 2016 & yr <= 2021) %>%
  select(om, yr, date)
ggplot() +
  geom_sf(data = okcounty, fill = NA) +
  geom_sf(data = tpoint_16_21) +
  theme_bw()

ggplot() +
  geom_sf(data = okcounty, fill = NA) +
  geom_sf(data = tpath_16_21, color = "red") +
  theme_void()

ggplot() +
  geom_sf(data = tpoint_16_21,
          aes(color = as.factor(yr))) +
  geom_sf(data = okcounty, fill = NA) +
  scale_color_discrete(name = "Year") +
  coord_sf(datum = NA) +
  theme_void()

ggplot() +
  geom_sf(data = okcounty, 
          fill = NA,
          color = "gray") +
  geom_sf(data = tpoint_16_21,size = 0.75) +
  facet_wrap(vars(yr), ncol = 2) +
  coord_sf(datum = NA) +
  theme_void()

countypnt <- st_join(tpoint_16_21, okcounty)
glimpse(countypnt)
Rows: 434
Columns: 11
$ om       <dbl> 613662, 613675, 613676, 613677, 613678, 613727, 613728, 613729, 613730, 613731, 613763, 613764, 61376…
$ yr       <dbl> 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016,…
$ date     <chr> "2016-03-23", "2016-03-30", "2016-03-30", "2016-03-30", "2016-03-30", "2016-04-15", "2016-04-15", "20…
$ STATEFP  <chr> "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40",…
$ COUNTYFP <chr> "001", "113", "105", "131", "035", "139", "139", "139", "139", "139", "017", "109", "109", "113", "12…
$ COUNTYNS <chr> "01101788", "01101844", "01101840", "01101853", "01101805", "01101857", "01101857", "01101857", "0110…
$ AFFGEOID <chr> "0500000US40001", "0500000US40113", "0500000US40105", "0500000US40131", "0500000US40035", "0500000US4…
$ GEOID    <chr> "40001", "40113", "40105", "40131", "40035", "40139", "40139", "40139", "40139", "40139", "40017", "4…
$ NAME     <chr> "Adair", "Osage", "Nowata", "Rogers", "Craig", "Texas", "Texas", "Texas", "Texas", "Texas", "Canadian…
$ LSAD     <chr> "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06",…
$ geometry <POINT [°]> POINT (-94.5042 35.6916), POINT (-96.0151 36.2151), POINT (-95.5523 36.7291), POINT (-95.6384 3…
# convert to a non spatial dataframe
countypnt <- st_drop_geometry(countypnt)
countysum <- countypnt %>%
  group_by(GEOID) %>%
  summarize(tcnt = n())
glimpse(countysum)
Rows: 75
Columns: 2
$ GEOID <chr> "40001", "40005", "40007", "40009", "40011", "40013", "40015", "40017", "40019", "40021", "40023", "4002…
$ tcnt  <int> 6, 3, 4, 8, 1, 4, 10, 5, 7, 5, 3, 12, 10, 5, 5, 1, 7, 9, 7, 8, 2, 2, 2, 3, 9, 5, 4, 4, 2, 1, 4, 3, 9, 1,…
countymap <- okcounty %>%
  left_join(countysum, by = "GEOID") %>%
  replace(is.na(.), 0) %>%
  mutate(area = st_area(okcounty),
         tdens = 10^6 * 10^3 * tcnt / area) %>%
  drop_units()
glimpse(countymap)
Rows: 77
Columns: 11
$ STATEFP  <chr> "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40", "40",…
$ COUNTYFP <chr> "077", "025", "011", "107", "105", "153", "001", "053", "059", "073", "129", "015", "097", "033", "14…
$ COUNTYNS <chr> "01101826", "01101800", "01101793", "01101841", "01101840", "01101864", "01101788", "01101814", "0110…
$ AFFGEOID <chr> "0500000US40077", "0500000US40025", "0500000US40011", "0500000US40107", "0500000US40105", "0500000US4…
$ GEOID    <chr> "40077", "40025", "40011", "40107", "40105", "40153", "40001", "40053", "40059", "40073", "40129", "4…
$ NAME     <chr> "Latimer", "Cimarron", "Blaine", "Okfuskee", "Nowata", "Woodward", "Adair", "Grant", "Harper", "Kingf…
$ LSAD     <chr> "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06", "06",…
$ tcnt     <dbl> 1, 12, 1, 10, 6, 2, 6, 0, 4, 9, 3, 10, 12, 1, 2, 8, 13, 4, 5, 5, 5, 1, 9, 3, 16, 6, 9, 1, 8, 5, 4, 7,…
$ geometry <POLYGON [°]> POLYGON ((-95.50766 35.0292..., POLYGON ((-103.0025 36.6751..., POLYGON ((-98.6369 36.16489..…
$ area     <dbl> 1890663261, 4766283042, 2427121029, 1657249513, 1503893122, 3227039659, 1493619771, 2597526414, 26851…
$ tdens    <dbl> 0.5289149, 2.5176851, 0.4120108, 6.0340944, 3.9896452, 0.6197631, 4.0170866, 0.0000000, 1.4896951, 3.…
st_write(countymap, dsn = "oktornado.gpkg",
         layer = "countysum",
         delete_dsn = TRUE)
st_write(countymap, dsn = "oktornado.geojson",
         layeroptions = "RFC7946 = YES")
# proud to say the highest tornado density is my home town, Tulsa County
ggplot(data = countymap) +
  geom_sf(aes(fill = tdens)) +
  theme_void()

st_geometry_type(okcounty, by_geometry = FALSE)
[1] POLYGON
18 Levels: GEOMETRY POINT LINESTRING POLYGON MULTIPOINT MULTILINESTRING ... TRIANGLE
okcntrd = st_centroid(countymap)
Warning: st_centroid assumes attributes are constant over geometries
st_geometry_type(okcntrd, by_geometry = FALSE)
[1] POINT
18 Levels: GEOMETRY POINT LINESTRING POLYGON MULTIPOINT MULTILINESTRING ... TRIANGLE
ggplot() +
  geom_sf(data = okcntrd, aes(size = tcnt)) +
  geom_sf(data = okcounty, fill = NA) +
  theme_void()

ggplot(data = countymap) +
  geom_sf(aes(fill = tdens)) +
  scale_fill_distiller(name = expression("Tornadoes/1000 km"^2),
                       palette = "YlOrRd",
                       breaks = pretty_breaks(),
                       direction = 1) +
  theme_void() +
  theme(legend.position = "bottom")

numclas <- 4
qbrks <- seq(0, 1, length.out = numclas + 1)
qbrks
[1] 0.00 0.25 0.50 0.75 1.00
countymap <- countymap %>%
  mutate(tdens_c1 = cut(tdens,
                        breaks = quantile(tdens, breaks = qbrks),
                        include.lowest = T))


ggplot(data = countymap) +
  geom_sf(aes(fill = tdens_c1)) +
  scale_fill_brewer(name = expression("Tornadoes/1000 km"^2),
                    palette = "YlOrRd") +
  theme_void() +
  theme(legend.position = "bottom")

maxcnt <- max(okcntrd$tcnt)
brkpts <- c(0, 2, 5, 10, maxcnt)
okcntrd <- okcntrd %>%
  mutate(tcnt_c1 = cut(tcnt,
                       breaks = brkpts,
                       include.lowest = T))

ggplot(data = okcntrd) +
  geom_sf(aes(size = tcnt_c1)) +
  scale_size_discrete(name="Tornadoes") +
  geom_sf(data = okcounty, fill = NA) +
  theme_void() +
  theme(legend.position = "bottom")
Warning: Using size for a discrete variable is not advised.

ggsave("tornado.png", 
       width = 6, 
       height = 4, 
       dpi = 300)
ggsave("tornado2.png", 
       width = 15, 
       height = 10, 
       units = "cm", 
       dpi = 100)
choropleth <- ggplot(data = countymap) +
  geom_sf(aes(fill = tdens_c1)) +
  scale_fill_brewer(name="Density",   
                    palette = "YlOrRd") +
  theme_void()

gradsymbol <- ggplot(data = okcntrd) +
  geom_sf(aes(size = tcnt_c1)) +
  scale_size_discrete(name="Count") +
  geom_sf(data = okcounty, fill = NA) +
  theme_void()
Warning: Using size for a discrete variable is not advised.
ggsave("choropleth.tiff", 
       plot = choropleth,
       width = 6, 
       height = 4, 
       dpi = 300, 
       compression = "lzw")

ggsave("gradsymbol.tiff",
       plot = gradsymbol,
       width = 6, 
       height = 4, 
       dpi = 300, 
       compression = "lzw")
plot_grid(choropleth, gradsymbol, 
          labels = c("A) Choropleth Map", 
                     "B) Graduated Symbol Map",
                     label_size = 12),
          ncol = 1, 
          hjust = 0, 
          label_x = 0)

tpath_years <- ggplot() +
                  geom_sf(data = tpath_16_21,
                          aes(color = as.factor(yr))) +
                  geom_sf(data = okcounty, fill = NA) +
                  scale_color_discrete(name = "Year") +
                  coord_sf(datum = NA) +
                  theme_void()

tpoint_years <- ggplot() +
                  geom_sf(data = tpoint_16_21,
                          aes(color = as.factor(yr))) +
                  geom_sf(data = okcounty, fill = NA) +
                  scale_color_discrete(name = "Year") +
                  coord_sf(datum = NA) +
                  theme_void()

ggsave("tpath_years.tiff", 
       plot = choropleth,
       width = 6, 
       height = 6, 
       dpi = 300, 
       compression = "lzw")

ggsave("tpoint_years.tiff", 
       plot = choropleth,
       width = 6, 
       height = 6, 
       dpi = 300, 
       compression = "lzw")

plot_grid(tpath_years, tpoint_years, 
          labels = c("A) Tornado Paths", 
                     "B) Tornado Points",
                     label_size = 12),
          ncol = 1, 
          rel_heights = c(1, 1),
          align = "hv",
          vjust = 5)
ggplot(data = countymap) +
  geom_sf(aes(fill = tdens)) +
  scale_fill_distiller(name = expression("Tornadoes/1000 km"^2),
                       palette = "YlOrRd",
                       breaks = pretty_breaks(),
                       direction = 1) +

  theme_void() +
  theme(legend.position = "bottom")

df_join <- countymap %>%
  left_join(countypnt, by = "GEOID") %>%
  replace(is.na(.), 0) %>%
  filter(yr != 0)  

ggplot(data = df_join) +
  geom_sf(aes(fill = tdens)) +
  geom_sf(data = okcounty, 
          fill = NA,
          color = "gray") +
  scale_fill_distiller(name = expression("Tornadoes/1000 km"^2),
                       palette = "YlOrRd",
                       breaks = pretty_breaks(),
                       direction = 1) +
  facet_wrap(vars(yr), ncol = 2) +
  coord_sf(datum = NA) +
  theme_void() +
  theme(legend.position = "bottom")

url <- "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.geojson"
earthquakes <- readOGR(url)
Warning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among others
OGR data source with driver: GeoJSON 
Source: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_month.geojson", layer: "2.5_month"
with 1947 features
It has 27 fields
Integer64 fields read as strings:  time updated 
eqsf <- st_as_sf(earthquakes)
faults_url <- "https://services.arcgis.com/jIL9msH9OI208GCb/ArcGIS/rest/services/Active_Faults/FeatureServer/0/query?where=1%3D1&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&resultType=none&distance=0.0&units=esriSRUnit_Meter&relationParam=&returnGeodetic=false&outFields=*&returnGeometry=true&featureEncoding=esriDefault&multipatchOption=xyFootprint&maxAllowableOffset=&geometryPrecision=&outSR=&defaultSR=&datumTransformation=&applyVCSProjection=false&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&returnQueryGeometry=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&having=&resultOffset=&resultRecordCount=&returnZ=false&returnM=false&returnExceededLimitFeatures=true&quantizationParameters=&sqlFormat=none&f=pgeojson&token="
faults <-readOGR(faults_url)
Warning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among othersWarning: OGR support is provided by the sf and terra packages among others
OGR data source with driver: GeoJSON 
Source: "https://services.arcgis.com/jIL9msH9OI208GCb/ArcGIS/rest/services/Active_Faults/FeatureServer/0/query?where=1%3D1&objectIds=&time=&geometry=&geometryType=esriGeometryEnvelope&inSR=&spatialRel=esriSpatialRelIntersects&resultType=none&distance=0.0&units=esriSRUnit_Meter&relationParam=&returnGeodetic=false&outFields=*&returnGeometry=true&featureEncoding=esriDefault&multipatchOption=xyFootprint&maxAllowableOffset=&geometryPrecision=&outSR=&defaultSR=&datumTransformation=&applyVCSProjection=false&returnIdsOnly=false&returnUniqueIdsOnly=false&returnCountOnly=false&returnExtentOnly=false&returnQueryGeometry=false&returnDistinctValues=false&cacheHint=false&orderByFields=&groupByFieldsForStatistics=&outStatistics=&having=&resultOffset=&resultRecordCount=&returnZ=false&returnM=false&returnExceededLimitFeatures=true&quantizationParameters=&sqlFormat=none&f=pgeojson&token=", layer: "OGRGeoJSON"
with 16121 features
It has 6 fields
faults_sf <- st_as_sf(faults)
pal <- colorBin(
  palette = "Spectral",
  domain = eqsf$mag,
  reverse = TRUE,
  bins = 5
)

leaflet() %>%
  addTiles() %>%
  setView(-117.841293, 46.195042, 3) %>%
  addProviderTiles(providers$CartoDB, group = "Grayscale") %>% 
  addProviderTiles(providers$Esri.WorldTerrain, group = "Terrain") %>%
  addPolylines(data = faults_sf, group = "vectorData") %>%
  addCircleMarkers(data = eqsf,
                   fillColor = ~pal(mag),
                   radius = ~eqsf$mag * 2,
                   stroke = FALSE,
                   color = "Spectral",
                   fillOpacity = 0.6,
                   popup = paste0(
                     "<strong>Title:</strong> ", eqsf$title,
                     "<br><strong>Magnitude:</strong> ", eqsf$mag,
                     "<br><strong>Intensity:</strong> ", eqsf$mmi,
                     "<br><strong>Sig:</strong> ", eqsf$sig
                   ),
                   group = "vectorData"
  ) %>% 
  addLegend(pal = pal, values = eqsf$mag, position = "bottomleft", title = "Magnitude") %>%
  addLayersControl(overlayGroups = c("vectorData"), baseGroups = c("Terrain", "Grayscale"))
LS0tDQp0aXRsZTogIk9rbGFob21hIFRvcm5hZG9lcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyfQ0KbGlicmFyeShzZikgICAgICAgICAgIA0KbGlicmFyeShyZ2RhbCkgICAgICAgIA0KbGlicmFyeShnZ3Bsb3QyKSAgICAgIA0KbGlicmFyeShkcGx5cikgICAgICAgIA0KbGlicmFyeSh0aWR5cikgICAgICAgIA0KbGlicmFyeShzY2FsZXMpICAgICAgIA0KbGlicmFyeShSQ29sb3JCcmV3ZXIpIA0KbGlicmFyeSh1bml0cykNCmxpYnJhcnkoY293cGxvdCkNCmxpYnJhcnkoaGVyZSkNCmBgYA0KYGBge3J9DQpva2NvdW50eSA8LSBzdF9yZWFkKGhlcmUoImRhdGEiLCAib2tfY291bnRpZXMuc2hwIiksIHF1aWV0ID0gVFJVRSkNCnRwb2ludCA8LSBzdF9yZWFkKGhlcmUoImRhdGEiLCAib2tfdG9ybmFkb19wb2ludC5zaHAiKSwgcXVpZXQgPSBUUlVFKQ0KdHBhdGggPC0gc3RfcmVhZChoZXJlKCJkYXRhIiwgIm9rX3Rvcm5hZG9fcGF0aC5zaHAiKSwgcXVpZXQgPSBUUlVFKQ0KDQpjbGFzcyhva2NvdW50eSkNCmdsaW1wc2Uob2tjb3VudHkpDQpgYGANCmBgYHtyfQ0Kb2tjb3VudHlfc3AgPC0gYXMob2tjb3VudHksICdTcGF0aWFsJykNCmNsYXNzKG9rY291bnR5X3NwKQ0KYGBgDQpgYGB7cn0NCm9rY291bnR5X3NmIDwtIHN0X2FzX3NmKG9rY291bnR5X3NwKQ0KY2xhc3Mob2tjb3VudHlfc2YpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBva2NvdW50eSkgKw0KICBnZW9tX3NmKGZpbGwgPSBOQSkNCmBgYA0KYGBge3J9DQpuYW1lcyh0cG9pbnQpDQpgYGANCmBgYHtyfQ0KdHBvaW50XzE2XzIxIDwtIHRwb2ludCAlPiUNCiAgZmlsdGVyKHlyID49IDIwMTYgJiB5ciA8PSAyMDIxKSAlPiUNCiAgc2VsZWN0KG9tLCB5ciwgZGF0ZSkNCg0KdHBhdGhfMTZfMjEgPC0gdHBhdGggJT4lDQogIGZpbHRlcih5ciA+PSAyMDE2ICYgeXIgPD0gMjAyMSkgJT4lDQogIHNlbGVjdChvbSwgeXIsIGRhdGUpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBva2NvdW50eSwgZmlsbCA9IE5BKSArDQogIGdlb21fc2YoZGF0YSA9IHRwb2ludF8xNl8yMSkgKw0KICB0aGVtZV9idygpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IG9rY291bnR5LCBmaWxsID0gTkEpICsNCiAgZ2VvbV9zZihkYXRhID0gdHBhdGhfMTZfMjEsIGNvbG9yID0gInJlZCIpICsNCiAgdGhlbWVfdm9pZCgpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSB0cG9pbnRfMTZfMjEsDQogICAgICAgICAgYWVzKGNvbG9yID0gYXMuZmFjdG9yKHlyKSkpICsNCiAgZ2VvbV9zZihkYXRhID0gb2tjb3VudHksIGZpbGwgPSBOQSkgKw0KICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lID0gIlllYXIiKSArDQogIGNvb3JkX3NmKGRhdHVtID0gTkEpICsNCiAgdGhlbWVfdm9pZCgpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBva2NvdW50eSwgDQogICAgICAgICAgZmlsbCA9IE5BLA0KICAgICAgICAgIGNvbG9yID0gImdyYXkiKSArDQogIGdlb21fc2YoZGF0YSA9IHRwb2ludF8xNl8yMSxzaXplID0gMC43NSkgKw0KICBmYWNldF93cmFwKHZhcnMoeXIpLCBuY29sID0gMikgKw0KICBjb29yZF9zZihkYXR1bSA9IE5BKSArDQogIHRoZW1lX3ZvaWQoKQ0KYGBgDQpgYGB7cn0NCmNvdW50eXBudCA8LSBzdF9qb2luKHRwb2ludF8xNl8yMSwgb2tjb3VudHkpDQpnbGltcHNlKGNvdW50eXBudCkNCg0KIyBjb252ZXJ0IHRvIGEgbm9uIHNwYXRpYWwgZGF0YWZyYW1lDQpjb3VudHlwbnQgPC0gc3RfZHJvcF9nZW9tZXRyeShjb3VudHlwbnQpDQpjb3VudHlzdW0gPC0gY291bnR5cG50ICU+JQ0KICBncm91cF9ieShHRU9JRCkgJT4lDQogIHN1bW1hcml6ZSh0Y250ID0gbigpKQ0KZ2xpbXBzZShjb3VudHlzdW0pDQpgYGANCmBgYHtyfQ0KY291bnR5bWFwIDwtIG9rY291bnR5ICU+JQ0KICBsZWZ0X2pvaW4oY291bnR5c3VtLCBieSA9ICJHRU9JRCIpICU+JQ0KICByZXBsYWNlKGlzLm5hKC4pLCAwKSAlPiUNCiAgbXV0YXRlKGFyZWEgPSBzdF9hcmVhKG9rY291bnR5KSwNCiAgICAgICAgIHRkZW5zID0gMTBeNiAqIDEwXjMgKiB0Y250IC8gYXJlYSkgJT4lDQogIGRyb3BfdW5pdHMoKQ0KZ2xpbXBzZShjb3VudHltYXApDQpgYGANCmBgYHtyfQ0Kc3Rfd3JpdGUoY291bnR5bWFwLCBkc24gPSAib2t0b3JuYWRvLmdwa2ciLA0KICAgICAgICAgbGF5ZXIgPSAiY291bnR5c3VtIiwNCiAgICAgICAgIGRlbGV0ZV9kc24gPSBUUlVFKQ0KYGBgDQpgYGB7cn0NCnN0X3dyaXRlKGNvdW50eW1hcCwgZHNuID0gIm9rdG9ybmFkby5nZW9qc29uIiwNCiAgICAgICAgIGxheWVyb3B0aW9ucyA9ICJSRkM3OTQ2ID0gWUVTIikNCmBgYA0KYGBge3J9DQojIHByb3VkIHRvIHNheSB0aGUgaGlnaGVzdCB0b3JuYWRvIGRlbnNpdHkgaXMgbXkgaG9tZSB0b3duLCBUdWxzYSBDb3VudHkNCmdncGxvdChkYXRhID0gY291bnR5bWFwKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSB0ZGVucykpICsNCiAgdGhlbWVfdm9pZCgpDQpgYGANCmBgYHtyfQ0Kc3RfZ2VvbWV0cnlfdHlwZShva2NvdW50eSwgYnlfZ2VvbWV0cnkgPSBGQUxTRSkNCg0Kb2tjbnRyZCA9IHN0X2NlbnRyb2lkKGNvdW50eW1hcCkNCnN0X2dlb21ldHJ5X3R5cGUob2tjbnRyZCwgYnlfZ2VvbWV0cnkgPSBGQUxTRSkNCmBgYA0KDQpgYGB7cn0NCmdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gb2tjbnRyZCwgYWVzKHNpemUgPSB0Y250KSkgKw0KICBnZW9tX3NmKGRhdGEgPSBva2NvdW50eSwgZmlsbCA9IE5BKSArDQogIHRoZW1lX3ZvaWQoKQ0KYGBgDQpgYGB7cn0NCmdncGxvdChkYXRhID0gY291bnR5bWFwKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSB0ZGVucykpICsNCiAgc2NhbGVfZmlsbF9kaXN0aWxsZXIobmFtZSA9IGV4cHJlc3Npb24oIlRvcm5hZG9lcy8xMDAwIGttIl4yKSwNCiAgICAgICAgICAgICAgICAgICAgICAgcGFsZXR0ZSA9ICJZbE9yUmQiLA0KICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBwcmV0dHlfYnJlYWtzKCksDQogICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9IDEpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQoNCmBgYA0KYGBge3J9DQpudW1jbGFzIDwtIDQNCnFicmtzIDwtIHNlcSgwLCAxLCBsZW5ndGgub3V0ID0gbnVtY2xhcyArIDEpDQpxYnJrcw0KDQpjb3VudHltYXAgPC0gY291bnR5bWFwICU+JQ0KICBtdXRhdGUodGRlbnNfYzEgPSBjdXQodGRlbnMsDQogICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBxdWFudGlsZSh0ZGVucywgYnJlYWtzID0gcWJya3MpLA0KICAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBUKSkNCg0KDQpnZ3Bsb3QoZGF0YSA9IGNvdW50eW1hcCkgKw0KICBnZW9tX3NmKGFlcyhmaWxsID0gdGRlbnNfYzEpKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKG5hbWUgPSBleHByZXNzaW9uKCJUb3JuYWRvZXMvMTAwMCBrbSJeMiksDQogICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAiWWxPclJkIikgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCmBgYA0KYGBge3J9DQptYXhjbnQgPC0gbWF4KG9rY250cmQkdGNudCkNCmJya3B0cyA8LSBjKDAsIDIsIDUsIDEwLCBtYXhjbnQpDQpva2NudHJkIDwtIG9rY250cmQgJT4lDQogIG11dGF0ZSh0Y250X2MxID0gY3V0KHRjbnQsDQogICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGJya3B0cywNCiAgICAgICAgICAgICAgICAgICAgICAgaW5jbHVkZS5sb3dlc3QgPSBUKSkNCg0KZ2dwbG90KGRhdGEgPSBva2NudHJkKSArDQogIGdlb21fc2YoYWVzKHNpemUgPSB0Y250X2MxKSkgKw0KICBzY2FsZV9zaXplX2Rpc2NyZXRlKG5hbWU9IlRvcm5hZG9lcyIpICsNCiAgZ2VvbV9zZihkYXRhID0gb2tjb3VudHksIGZpbGwgPSBOQSkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikNCmBgYA0KYGBge3J9DQpnZ3NhdmUoInRvcm5hZG8ucG5nIiwgDQogICAgICAgd2lkdGggPSA2LCANCiAgICAgICBoZWlnaHQgPSA0LCANCiAgICAgICBkcGkgPSAzMDApDQpnZ3NhdmUoInRvcm5hZG8yLnBuZyIsIA0KICAgICAgIHdpZHRoID0gMTUsIA0KICAgICAgIGhlaWdodCA9IDEwLCANCiAgICAgICB1bml0cyA9ICJjbSIsIA0KICAgICAgIGRwaSA9IDEwMCkNCmBgYA0KYGBge3J9DQpjaG9yb3BsZXRoIDwtIGdncGxvdChkYXRhID0gY291bnR5bWFwKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSB0ZGVuc19jMSkpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIobmFtZT0iRGVuc2l0eSIsICAgDQogICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAiWWxPclJkIikgKw0KICB0aGVtZV92b2lkKCkNCg0KZ3JhZHN5bWJvbCA8LSBnZ3Bsb3QoZGF0YSA9IG9rY250cmQpICsNCiAgZ2VvbV9zZihhZXMoc2l6ZSA9IHRjbnRfYzEpKSArDQogIHNjYWxlX3NpemVfZGlzY3JldGUobmFtZT0iQ291bnQiKSArDQogIGdlb21fc2YoZGF0YSA9IG9rY291bnR5LCBmaWxsID0gTkEpICsNCiAgdGhlbWVfdm9pZCgpDQoNCmdnc2F2ZSgiY2hvcm9wbGV0aC50aWZmIiwgDQogICAgICAgcGxvdCA9IGNob3JvcGxldGgsDQogICAgICAgd2lkdGggPSA2LCANCiAgICAgICBoZWlnaHQgPSA0LCANCiAgICAgICBkcGkgPSAzMDAsIA0KICAgICAgIGNvbXByZXNzaW9uID0gImx6dyIpDQoNCmdnc2F2ZSgiZ3JhZHN5bWJvbC50aWZmIiwNCiAgICAgICBwbG90ID0gZ3JhZHN5bWJvbCwNCiAgICAgICB3aWR0aCA9IDYsIA0KICAgICAgIGhlaWdodCA9IDQsIA0KICAgICAgIGRwaSA9IDMwMCwgDQogICAgICAgY29tcHJlc3Npb24gPSAibHp3IikNCmBgYA0KYGBge3J9DQpwbG90X2dyaWQoY2hvcm9wbGV0aCwgZ3JhZHN5bWJvbCwgDQogICAgICAgICAgbGFiZWxzID0gYygiQSkgQ2hvcm9wbGV0aCBNYXAiLCANCiAgICAgICAgICAgICAgICAgICAgICJCKSBHcmFkdWF0ZWQgU3ltYm9sIE1hcCIsDQogICAgICAgICAgICAgICAgICAgICBsYWJlbF9zaXplID0gMTIpLA0KICAgICAgICAgIG5jb2wgPSAxLCANCiAgICAgICAgICBoanVzdCA9IDAsIA0KICAgICAgICAgIGxhYmVsX3ggPSAwLCANCiAgICAgICAgICBhbGlnbiA9ICJodiIpDQpgYGANCg0KYGBge3J9DQp0cGF0aF95ZWFycyA8LSBnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICBnZW9tX3NmKGRhdGEgPSB0cGF0aF8xNl8yMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGNvbG9yID0gYXMuZmFjdG9yKHlyKSkpICsNCiAgICAgICAgICAgICAgICAgIGdlb21fc2YoZGF0YSA9IG9rY291bnR5LCBmaWxsID0gTkEpICsNCiAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKG5hbWUgPSAiWWVhciIpICsNCiAgICAgICAgICAgICAgICAgIGNvb3JkX3NmKGRhdHVtID0gTkEpICsNCiAgICAgICAgICAgICAgICAgIHRoZW1lX3ZvaWQoKQ0KDQp0cG9pbnRfeWVhcnMgPC0gZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgZ2VvbV9zZihkYXRhID0gdHBvaW50XzE2XzIxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhZXMoY29sb3IgPSBhcy5mYWN0b3IoeXIpKSkgKw0KICAgICAgICAgICAgICAgICAgZ2VvbV9zZihkYXRhID0gb2tjb3VudHksIGZpbGwgPSBOQSkgKw0KICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3JfZGlzY3JldGUobmFtZSA9ICJZZWFyIikgKw0KICAgICAgICAgICAgICAgICAgY29vcmRfc2YoZGF0dW0gPSBOQSkgKw0KICAgICAgICAgICAgICAgICAgdGhlbWVfdm9pZCgpDQoNCmdnc2F2ZSgidHBhdGhfeWVhcnMudGlmZiIsIA0KICAgICAgIHBsb3QgPSBjaG9yb3BsZXRoLA0KICAgICAgIHdpZHRoID0gNiwgDQogICAgICAgaGVpZ2h0ID0gNiwgDQogICAgICAgZHBpID0gMzAwLCANCiAgICAgICBjb21wcmVzc2lvbiA9ICJsenciKQ0KDQpnZ3NhdmUoInRwb2ludF95ZWFycy50aWZmIiwgDQogICAgICAgcGxvdCA9IGNob3JvcGxldGgsDQogICAgICAgd2lkdGggPSA2LCANCiAgICAgICBoZWlnaHQgPSA2LCANCiAgICAgICBkcGkgPSAzMDAsIA0KICAgICAgIGNvbXByZXNzaW9uID0gImx6dyIpDQoNCnBsb3RfZ3JpZCh0cGF0aF95ZWFycywgdHBvaW50X3llYXJzLCANCiAgICAgICAgICBsYWJlbHMgPSBjKCJBKSBUb3JuYWRvIFBhdGhzIiwgDQogICAgICAgICAgICAgICAgICAgICAiQikgVG9ybmFkbyBQb2ludHMiLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDEyKSwNCiAgICAgICAgICBuY29sID0gMSwgDQogICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDEsIDEpLA0KICAgICAgICAgIGFsaWduID0gImh2IiwNCiAgICAgICAgICB2anVzdCA9IDUpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBjb3VudHltYXApICsNCiAgZ2VvbV9zZihhZXMoZmlsbCA9IHRkZW5zKSkgKw0KICBzY2FsZV9maWxsX2Rpc3RpbGxlcihuYW1lID0gZXhwcmVzc2lvbigiVG9ybmFkb2VzLzEwMDAga20iXjIpLA0KICAgICAgICAgICAgICAgICAgICAgICBwYWxldHRlID0gIllsT3JSZCIsDQogICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHByZXR0eV9icmVha3MoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gMSkgKw0KDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KDQpgYGANCmBgYHtyfQ0KIyBwYXJ0IGIgbGFiIDQNCmRmX2pvaW4gPC0gY291bnR5bWFwICU+JQ0KICBsZWZ0X2pvaW4oY291bnR5cG50LCBieSA9ICJHRU9JRCIpICU+JQ0KICByZXBsYWNlKGlzLm5hKC4pLCAwKSAlPiUNCiAgZmlsdGVyKHlyICE9IDApICANCg0KZ2dwbG90KGRhdGEgPSBkZl9qb2luKSArDQogIGdlb21fc2YoYWVzKGZpbGwgPSB0ZGVucykpICsNCiAgZ2VvbV9zZihkYXRhID0gb2tjb3VudHksIA0KICAgICAgICAgIGZpbGwgPSBOQSwNCiAgICAgICAgICBjb2xvciA9ICJncmF5IikgKw0KICBzY2FsZV9maWxsX2Rpc3RpbGxlcihuYW1lID0gZXhwcmVzc2lvbigiVG9ybmFkb2VzLzEwMDAga20iXjIpLA0KICAgICAgICAgICAgICAgICAgICAgICBwYWxldHRlID0gIllsT3JSZCIsDQogICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHByZXR0eV9icmVha3MoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gMSkgKw0KICBmYWNldF93cmFwKHZhcnMoeXIpLCBuY29sID0gMikgKw0KICBjb29yZF9zZihkYXR1bSA9IE5BKSArDQogIHRoZW1lX3ZvaWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KYGBgDQpgYGB7cn0NCg0KYGBgDQpgYGB7cn0NCnVybCA8LSAiaHR0cHM6Ly9lYXJ0aHF1YWtlLnVzZ3MuZ292L2VhcnRocXVha2VzL2ZlZWQvdjEuMC9zdW1tYXJ5LzIuNV9tb250aC5nZW9qc29uIg0KZWFydGhxdWFrZXMgPC0gcmVhZE9HUih1cmwpDQplcXNmIDwtIHN0X2FzX3NmKGVhcnRocXVha2VzKQ0KZmF1bHRzX3VybCA8LSAiaHR0cHM6Ly9zZXJ2aWNlcy5hcmNnaXMuY29tL2pJTDltc0g5T0kyMDhHQ2IvQXJjR0lTL3Jlc3Qvc2VydmljZXMvQWN0aXZlX0ZhdWx0cy9GZWF0dXJlU2VydmVyLzAvcXVlcnk/d2hlcmU9MSUzRDEmb2JqZWN0SWRzPSZ0aW1lPSZnZW9tZXRyeT0mZ2VvbWV0cnlUeXBlPWVzcmlHZW9tZXRyeUVudmVsb3BlJmluU1I9JnNwYXRpYWxSZWw9ZXNyaVNwYXRpYWxSZWxJbnRlcnNlY3RzJnJlc3VsdFR5cGU9bm9uZSZkaXN0YW5jZT0wLjAmdW5pdHM9ZXNyaVNSVW5pdF9NZXRlciZyZWxhdGlvblBhcmFtPSZyZXR1cm5HZW9kZXRpYz1mYWxzZSZvdXRGaWVsZHM9KiZyZXR1cm5HZW9tZXRyeT10cnVlJmZlYXR1cmVFbmNvZGluZz1lc3JpRGVmYXVsdCZtdWx0aXBhdGNoT3B0aW9uPXh5Rm9vdHByaW50Jm1heEFsbG93YWJsZU9mZnNldD0mZ2VvbWV0cnlQcmVjaXNpb249Jm91dFNSPSZkZWZhdWx0U1I9JmRhdHVtVHJhbnNmb3JtYXRpb249JmFwcGx5VkNTUHJvamVjdGlvbj1mYWxzZSZyZXR1cm5JZHNPbmx5PWZhbHNlJnJldHVyblVuaXF1ZUlkc09ubHk9ZmFsc2UmcmV0dXJuQ291bnRPbmx5PWZhbHNlJnJldHVybkV4dGVudE9ubHk9ZmFsc2UmcmV0dXJuUXVlcnlHZW9tZXRyeT1mYWxzZSZyZXR1cm5EaXN0aW5jdFZhbHVlcz1mYWxzZSZjYWNoZUhpbnQ9ZmFsc2Umb3JkZXJCeUZpZWxkcz0mZ3JvdXBCeUZpZWxkc0ZvclN0YXRpc3RpY3M9Jm91dFN0YXRpc3RpY3M9JmhhdmluZz0mcmVzdWx0T2Zmc2V0PSZyZXN1bHRSZWNvcmRDb3VudD0mcmV0dXJuWj1mYWxzZSZyZXR1cm5NPWZhbHNlJnJldHVybkV4Y2VlZGVkTGltaXRGZWF0dXJlcz10cnVlJnF1YW50aXphdGlvblBhcmFtZXRlcnM9JnNxbEZvcm1hdD1ub25lJmY9cGdlb2pzb24mdG9rZW49Ig0KZmF1bHRzIDwtcmVhZE9HUihmYXVsdHNfdXJsKQ0KZmF1bHRzX3NmIDwtIHN0X2FzX3NmKGZhdWx0cykNCmBgYA0KDQpgYGB7cn0NCnBhbCA8LSBjb2xvckJpbigNCiAgcGFsZXR0ZSA9ICJTcGVjdHJhbCIsDQogIGRvbWFpbiA9IGVxc2YkbWFnLA0KICByZXZlcnNlID0gVFJVRSwNCiAgYmlucyA9IDUNCikNCg0KbGVhZmxldCgpICU+JQ0KICBhZGRUaWxlcygpICU+JQ0KICBzZXRWaWV3KC0xMTcuODQxMjkzLCA0Ni4xOTUwNDIsIDMpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLCBncm91cCA9ICJHcmF5c2NhbGUiKSAlPiUgDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRUZXJyYWluLCBncm91cCA9ICJUZXJyYWluIikgJT4lDQogIGFkZFBvbHlsaW5lcyhkYXRhID0gZmF1bHRzX3NmLCBncm91cCA9ICJ2ZWN0b3JEYXRhIikgJT4lDQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGVxc2YsDQogICAgICAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnBhbChtYWcpLA0KICAgICAgICAgICAgICAgICAgIHJhZGl1cyA9IH5lcXNmJG1hZyAqIDIsDQogICAgICAgICAgICAgICAgICAgc3Ryb2tlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSAiU3BlY3RyYWwiLA0KICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC42LA0KICAgICAgICAgICAgICAgICAgIHBvcHVwID0gcGFzdGUwKA0KICAgICAgICAgICAgICAgICAgICAgIjxzdHJvbmc+VGl0bGU6PC9zdHJvbmc+ICIsIGVxc2YkdGl0bGUsDQogICAgICAgICAgICAgICAgICAgICAiPGJyPjxzdHJvbmc+TWFnbml0dWRlOjwvc3Ryb25nPiAiLCBlcXNmJG1hZywNCiAgICAgICAgICAgICAgICAgICAgICI8YnI+PHN0cm9uZz5JbnRlbnNpdHk6PC9zdHJvbmc+ICIsIGVxc2YkbW1pLA0KICAgICAgICAgICAgICAgICAgICAgIjxicj48c3Ryb25nPlNpZzo8L3N0cm9uZz4gIiwgZXFzZiRzaWcNCiAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICAgICAgIGdyb3VwID0gInZlY3RvckRhdGEiDQogICkgJT4lIA0KICBhZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSBlcXNmJG1hZywgcG9zaXRpb24gPSAiYm90dG9tbGVmdCIsIHRpdGxlID0gIk1hZ25pdHVkZSIpICU+JQ0KICBhZGRMYXllcnNDb250cm9sKG92ZXJsYXlHcm91cHMgPSBjKCJ2ZWN0b3JEYXRhIiksIGJhc2VHcm91cHMgPSBjKCJUZXJyYWluIiwgIkdyYXlzY2FsZSIpKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShtYXB2aWV3KQ0KbWFwdmlldyhlcXNmKQ0KYGBg